package com.example.demo;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.Pointcut;
import org.springframework.aop.config.AopConfigUtils;
import org.springframework.aop.support.AbstractPointcutAdvisor;
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.stereotype.Service;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author bigbird-0101
 * @date 2024-06-27 22:55
 */
public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext=new AnnotationConfigApplicationContext(Config.class,A.class,B.class);
        MaiPiao bean = annotationConfigApplicationContext.getBean(MaiPiao.class);
        bean.maiPiao();
        annotationConfigApplicationContext.close();
    }
    @Configuration
    public static class Config {
        @Bean
        public BeanFactoryPostProcessor forceAutoProxyCreatorToUseClassProxying() {
            return (beanFactory) -> {
                if (beanFactory instanceof BeanDefinitionRegistry registry) {
                    AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                    AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                }
            };
        }
        @Bean
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        public Test.LogAdvisor logAdvisor(){
            return new Test.LogAdvisor();
        }
    }

    public static class LogAdvisor extends AbstractPointcutAdvisor {
        public LogAdvisor() {
            System.out.println("LogAdvisor");
        }

        @Override
        public Pointcut getPointcut() {
            return new AnnotationMatchingPointcut(null,Log.class,false);
        }

        @Override
        public Advice getAdvice() {
            return new LogMethodInterceptor();
        }

        private static class LogMethodInterceptor implements MethodInterceptor {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before");
                Object result = invocation.proceed();
                System.out.println("after");
                return result;
            }
        }
    }

    public interface MaiPiao {
        void maiPiao();
    }
    /**
     * @author bigbird-0101
     * @date 2024-06-27 23:07
     */
    @Documented
    @Target({ElementType.METHOD,ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Log {
        String value() default "";
    }

    @Service
    public static class B {
        @Log("123")
        public void maiPiao()
        {
            System.out.println("B mai piao");
        }
    }

    @Service
    public static class A implements MaiPiao{
        @Autowired
        private B b;
        @Override
        public void maiPiao() {
            b.maiPiao();
        }
    }
}
